/*
@title: Pizzeria
@description: "Pizzeria" is a retro-themed game where you take on the role of a pizzeria worker responsible for handling various tasks in the kitchen. Players create dough, bake it into pizzas in the oven, and deliver the finished pizzas to the chef to earn money and progress through levels. The game challenges players to efficiently manage the pizza-making process to advance through increasingly complex levels.
@author: dilbert335
@tags: ['retro']
@addedOn: 2024-08-06
*/

//Adjust this to how many pizzas needed to advance
const PIZZAS_NEEDED = 3

const spriteKeys = {
  player: 'p',
  player2:'u',
  pizza: 'v',
  wall: 'w',
  oven: 'o',
  ovenFire: 'f',
  table: 't',
  dough: 'd',
  bg: 'z',
  player3: 'h',
  winPrize: 'n'
}
const initSprites = () => {
  const sprites = {
    player: bitmap`
................
................
.......000......
.......404......
.......444......
....344444......
....020244......
....444444......
.......0..3.....
.....3303333....
.......0..33....
.....00000......
....00...00.....
3333333333333333
3333333333333333
3333333333333333`,
    player2: bitmap`
..222222222222..
..222222222222..
...22222222222..
....22222222....
.....222222.....
.....0C000000...
....0C2CC2C0....
.....C0CC0C.....
.....CCCCCC.....
....33333333....
..CC3C660663CC..
..C.3C066603.C..
..C.33333333.C..
....33333333CCC.
......0..0..636.
......C..C...6..`,
    pizza: bitmap`
  ................
  ................
  ................
  ................
  ....99999999....
  ...9966666699...
  ...9663663669...
  ...9666666669...
  ...9636366369...
  ...9666666669...
  ...9963663699...
  ....99999999....
  ................
  ................
  ................
  ................`,
    wall: bitmap`
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999
  9999999999999999`,
    oven: bitmap`
  ................
  ................
  ................
  ...0000000000...
  ...0000000000...
  ...LLLLLLLLLL...
  ...L11000011L...
  ...L11111111L...
  ...L11111111L...
  ...L11111111L...
  ...LLLLLLLLLL...
  ...L........L...
  5555555555555555
  ................
  ................
  ................`,
    ovenFire: bitmap`
  ................
  ................
  ................
  ...0000000000...
  ...0000000000...
  ...LLLLLLLLLL...
  ...L33333333L...
  ...L39999993L...
  ...L39666693L...
  ...L39666693L...
  ...LLLLLLLLLL...
  ...L........L...
  5555555555555555
  ................
  ................
  ................`,
    table: bitmap`
  ................
  ................
  ................
  ................
  ................
  .CC..........CC.
  .CCCC000000CCCC.
  ..CCCCCCCCCCCC..
  ..CC0C9999C0CC..
  ..CC0C9999C0CC..
  ..CC0C9999C0CC..
  ..CCCCCCCCCCCC..
  .CCCC000000CCCC.
  .CC..........CC.
  ................
  ................`,
    dough: bitmap`
  ................
  ................
  ................
  ................
  .....CCCCCC.....
  ....C999999C....
  ....C999999C....
  ....C999999C....
  ....C999999C....
  ....C999999C....
  .....CCCCCC.....
  ................
  ................
  ................
  ................
  ................`,
    bg: bitmap`
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666
  6666666666666666`,
    player3:bitmap`
  ................
  ................
  ................
  ................
  ................
  ................
  DHHHD..........D
  DDHDD..........D
  DDDDDDDDDDDDDDDD
  D404D4444444444D
  333334444444444D
  000DDDDDDDDDDDDD
  0008888888888888
  0008888888888888
  8888888888888888
  8888888888888888`,
    winPrize: bitmap`
....66666666....
.6666FFFFFF6666.
.6..66FFFF66..6.
.6..66666666..6.
.66664633656666.
....66666666....
.....666666.....
......6666......
.......66.......
....66666666....
..006000000600..
..000000000000..
..000000000000..
..000000000000..
................
................`
  }

  setBackground(spriteKeys.bg)
  const excludeList = ['o', 'u']
  
  setLegend(
    ...Object.entries(sprites).map(sprite => ([
      spriteKeys[sprite[0]], sprite[1]]))
  )
  
  setSolids(Object.values(spriteKeys).filter(s => excludeList.indexOf(s) === -1))
  setPushables({
    [spriteKeys.player]: [spriteKeys.dough, spriteKeys.pizza, spriteKeys.player]
  })
}

let currentLevel = -1
let advancingLevel = false
let reset, nextLevel, levelDoughPositions

const initLevels = () => { 
  const levels = [
    map`
  wwwwwwww
  wo.....w
  w......w
  w..t...w
  w....whw
  w....www
  wp....uw
  wwwwwwww`,
    map`
  wwwwwwww
  wu.....w
  ww.ww..w
  wo.....w
  ww.....w
  wwwt...w
  whwww.pw
  wwwwwwww`,
    map`
  wwwwwwww
  wu...www
  wo....ww
  ww.....w
  whwt...w
  ww.w...w
  wwp..www
  wwwwwwww`,
    map`
  wwwwwwwwww
  wo.....w.w
  w........w
  wwww.w.t.w
  whww....ww
  wwww..w..w
  ww.p....ww
  w..w.....w
  w....w..uw
  wwwwwwwwww`,
    map`
  wwwwwwwwwwwww
  w...........w
  w.p.....t...w
  wwww...www..w
  wo..........w
  ww....w..ww.w
  www..w...w..w
  wu....w..w..w
  www.....w...w
  ww...w......w
  www...ww.w..w
  whww........w
  wwwwwwwwwwwww`,
    map`
  w..www
  w...pw
  w....w
  w.wuww
  wotwhw
  wwwwww`,
    map`
  wwwwwwwwwwwwwww
  wo....ww.....ow
  w.....ww......w
  w..t..ww..t...w
  w.....ww...uwww
  w..........ww.w
  w.....p...ww.hw
  wwwwwwwwwwwwwww`,
    map`
  wwwwwwwwww
  wo..u..www
  w..t...www
  wp.....whw
  wwwwwwwwww`,
    map`
  wwwwwwwwwwwwwwww
  wo......p.....ww
  w...........wwww
  w...........wwww
  w........t.wwwww
  wwwwww..wwwwwwu.
  wwhwww..........
  wwwwww..........`,
    map`
  wwwwwwwwwwwwwwwwwwww
  w.p.....w.........tw
  w..................w
  wo......w..w.......w
  w.......ww.....w...w
  wwwwwww.....w......w
  w.uhw...w.w........w
  w..ww..............w
  w..ww.........w.w..w
  w.........w........w
  w..................w
  w........w..w.w.w..w
  ww.ww.......w....w.w
  w.....w....w...w...w
  w..................w
  w...ww.w....w......w
  w........w.........w
  w.....w............w
  w......w...........w
  wwwwwwwwwwwwwwwwwwww`,
  ]
  
  levelDoughPositions = [
    [5, 3],
    [5, 2],
    [4, 3],
    [2, 2],
    [2, 2], 
    [1, 1],
    [1, 2],
    [1, 1],
    [6, 3],
    [5, 4]
  ]

  nextLevel = (sound = true) => {
    currentLevel++
    if (levels[currentLevel]) {
      if (sound) {
        advancingLevel = true
        playTune(nextLevelSound)
        setTimeout(() => {
          advancingLevel = false
          setMap(levels[currentLevel])
        }, 4500)
      } else {
        setMap(levels[currentLevel])
      }
        
      
    } else {
      setMap(map`
wwwwwwwwww
wwwwwwwwww
wwwwwwwwhw
wwwwwwwwww
wv......vw
wv......vw
w...nn...w
wvvvvvvvvw
wwwwwwwwww
wwwwwwwwww`)
      setBackground('')
      clearText()
      addText("You win!", {x: 6, y: 8})
      playTune(tune`
196.07843137254903: G5/196.07843137254903 + F5/196.07843137254903 + E5/196.07843137254903 + D5/196.07843137254903 + C5/196.07843137254903,
196.07843137254903: B5/196.07843137254903 + A5/196.07843137254903,
196.07843137254903: A4^196.07843137254903 + G5/196.07843137254903 + F5/196.07843137254903,
196.07843137254903: A4^196.07843137254903,
196.07843137254903: A5~196.07843137254903 + G5~196.07843137254903 + F5~196.07843137254903,
196.07843137254903: B4^196.07843137254903 + E5~196.07843137254903,
196.07843137254903: C5^196.07843137254903 + F5~196.07843137254903,
196.07843137254903: G5^196.07843137254903 + A5^196.07843137254903 + F5~196.07843137254903,
196.07843137254903: D5~196.07843137254903,
196.07843137254903: D5~196.07843137254903,
196.07843137254903: D5~196.07843137254903,
196.07843137254903: A5/196.07843137254903 + F5/196.07843137254903,
196.07843137254903: B4/196.07843137254903 + G4^196.07843137254903,
196.07843137254903: E5/196.07843137254903 + G4^196.07843137254903 + C5~196.07843137254903,
196.07843137254903: G5/196.07843137254903 + A4^196.07843137254903 + D5~196.07843137254903,
196.07843137254903: B4^196.07843137254903 + E5~196.07843137254903,
196.07843137254903: B4/196.07843137254903 + F5~196.07843137254903,
196.07843137254903: G5~196.07843137254903,
196.07843137254903: F5/196.07843137254903,
196.07843137254903: E5/196.07843137254903,
196.07843137254903: D5/196.07843137254903,
196.07843137254903,
196.07843137254903: C5/196.07843137254903 + F5~196.07843137254903 + G5~196.07843137254903,
196.07843137254903: C5/196.07843137254903 + D5~196.07843137254903 + E5~196.07843137254903,
196.07843137254903: B4~196.07843137254903 + D5^196.07843137254903 + A4~196.07843137254903 + C5~196.07843137254903 + A5~196.07843137254903,
196.07843137254903: A5/196.07843137254903 + B4/196.07843137254903 + E4~196.07843137254903 + F4~196.07843137254903,
196.07843137254903: C5/196.07843137254903,
196.07843137254903: A4/196.07843137254903 + C5^196.07843137254903,
196.07843137254903: G4/196.07843137254903 + D5/196.07843137254903 + B4^196.07843137254903 + G5/196.07843137254903,
196.07843137254903: C5~196.07843137254903,
196.07843137254903: G5~196.07843137254903 + E5~196.07843137254903 + G4-196.07843137254903 + A4-196.07843137254903,
196.07843137254903: C5/196.07843137254903 + D5-196.07843137254903 + A4/196.07843137254903`)
    }
  }
  
  reset = () => {
    setMap(levels[currentLevel])
  }

  nextLevel(false)
}

let MONEY = 0
let giveMoney
const initMoney = () => {
  const updateMoneyText = () => {
    clearText()
    addText(`money: ${MONEY}`, {
      x: 6,
      y: 1,
      color: color`4`
    })
  }

  updateMoneyText()
  giveMoney = () => {
    MONEY += 5
  
    if (MONEY === PIZZAS_NEEDED * 5) {
      MONEY = 0
      nextLevel()
    }
    updateMoneyText()

  }
}

const initInput = () => {
  onInput("w", () => {
    if (advancingLevel) {return}
    const playerSprite = getFirst(spriteKeys.player)
    if (playerSprite.y > 0) {
      playerSprite.y -= 1
    }
  });
  onInput("s", () => {
    if (advancingLevel) {return}
    const playerSprite = getFirst(spriteKeys.player)
    if (playerSprite.y < height() - 1) {
      playerSprite.y += 1
    }
  });
  onInput("a", () => {
    if (advancingLevel) {return}
    const playerSprite = getFirst(spriteKeys.player)
    if (playerSprite.x > 0) {
      playerSprite.x -= 1
    }
  });
  onInput("d", () => {
    if (advancingLevel) {return}
    const playerSprite = getFirst(spriteKeys.player)
    if (playerSprite.x < width() - 1) {
      playerSprite.x += 1
    }
  });
  
  onInput("j", () => {
    if (advancingLevel) {return}
    if (getFirst(spriteKeys.dough)) {
      return;
    }
  
    const [x,y] = levelDoughPositions[currentLevel] ?? [1,1]
    addSprite(x, y, spriteKeys.dough)
  })
  
  onInput("l", () => {
    if (advancingLevel) {return}
    reset()
  })
}

initSprites()
initLevels()
initMoney()
initInput()

const bgMusic = tune`
468.75: F4~468.75 + D4~468.75,
468.75: G4~468.75 + E4~468.75 + C4~468.75,
468.75: G4~468.75 + E4~468.75 + C4~468.75,
468.75: G4~468.75 + E4~468.75 + C4~468.75,
468.75: F4~468.75 + D4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: F4~468.75 + D4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: F4~468.75 + D4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: F4~468.75 + D4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: F4~468.75 + D4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: F4~468.75 + D4~468.75 + E4~468.75,
468.75: G4~468.75 + C4~468.75 + E4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: E4~468.75 + G4~468.75 + C4~468.75,
468.75: F4~468.75 + D4~468.75,
468.75: G4~468.75 + E4~468.75 + C4~468.75,
468.75: G4~468.75 + E4~468.75 + C4~468.75,
468.75: G4~468.75 + E4~468.75 + C4~468.75`
let bgPlayback
const playBgMusic = () => {
  if (bgPlayback || advancingLevel) {return}
  bgPlayback = playTune(bgMusic, Infinity)
}
const stopBgMusic = () => {
  if (!bgPlayback) {return}
  bgPlayback.end()
  bgPlayback = undefined
}
playBgMusic()

const nextLevelSound = tune`
222.22222222222223: G4/222.22222222222223 + A4/222.22222222222223 + B4/222.22222222222223 + C5/222.22222222222223,
222.22222222222223: D5/222.22222222222223 + E5/222.22222222222223 + F5/222.22222222222223,
444.44444444444446,
222.22222222222223: G5/222.22222222222223 + F5/222.22222222222223 + E5/222.22222222222223 + D5/222.22222222222223,
222.22222222222223: C5/222.22222222222223 + B4/222.22222222222223,
222.22222222222223: A4/222.22222222222223 + G4/222.22222222222223,
222.22222222222223,
222.22222222222223: F4/222.22222222222223 + G4/222.22222222222223 + A4/222.22222222222223 + B4/222.22222222222223 + C5/222.22222222222223,
222.22222222222223,
222.22222222222223: F5/222.22222222222223,
222.22222222222223: E5/222.22222222222223 + D5/222.22222222222223 + C5/222.22222222222223,
222.22222222222223: B4/222.22222222222223 + A4/222.22222222222223,
222.22222222222223: G4/222.22222222222223,
222.22222222222223: C5/222.22222222222223 + D5/222.22222222222223 + E5/222.22222222222223 + F5/222.22222222222223 + G5/222.22222222222223,
222.22222222222223: G5/222.22222222222223,
222.22222222222223: G5/222.22222222222223,
222.22222222222223,
222.22222222222223: G5/222.22222222222223 + F5/222.22222222222223 + E5/222.22222222222223 + D5/222.22222222222223 + C5/222.22222222222223,
222.22222222222223: A4/222.22222222222223 + G4/222.22222222222223,
222.22222222222223: F4/222.22222222222223 + E4/222.22222222222223 + A4/222.22222222222223 + B4/222.22222222222223 + C5/222.22222222222223,
222.22222222222223: G5/222.22222222222223,
222.22222222222223: G5/222.22222222222223,
222.22222222222223,
222.22222222222223: G5/222.22222222222223,
222.22222222222223: G5/222.22222222222223 + F5/222.22222222222223 + E5/222.22222222222223 + D5/222.22222222222223 + C5/222.22222222222223,
222.22222222222223: G4/222.22222222222223 + F4/222.22222222222223,
222.22222222222223: F4/222.22222222222223,
222.22222222222223: F5/222.22222222222223 + G5/222.22222222222223,
222.22222222222223: A5/222.22222222222223,
222.22222222222223: A5/222.22222222222223,
222.22222222222223`

const setOvenFire = (fire) => {
  if (advancingLevel) {return}
  const oven = getFirst(spriteKeys.oven) ?? getFirst(spriteKeys.ovenFire)

  const x = oven.x
  const y = oven.y

  clearTile(x, y)
  addSprite(x, y, fire === true ? spriteKeys.ovenFire : spriteKeys.oven)
}

const doughInOvenSound = tune`
245.9016393442623: F4~245.9016393442623 + G4~245.9016393442623,
245.9016393442623: F4~245.9016393442623 + G4~245.9016393442623,
245.9016393442623: F5~245.9016393442623,
245.9016393442623: F5~245.9016393442623,
245.9016393442623: F4~245.9016393442623 + G4~245.9016393442623,
245.9016393442623: F4~245.9016393442623 + G4~245.9016393442623,
245.9016393442623: F5~245.9016393442623,
245.9016393442623: F5~245.9016393442623,
245.9016393442623: F4~245.9016393442623 + G4~245.9016393442623,
245.9016393442623: F4~245.9016393442623 + G4~245.9016393442623,
245.9016393442623: F5~245.9016393442623,
245.9016393442623: F5~245.9016393442623,
4918.0327868852455`
afterInput(() => {
  const doughSprite = getFirst(spriteKeys.dough)
  const pizzaSprite = getFirst(spriteKeys.pizza)

  if (pizzaSprite) {
    const player2Sprite = getFirst(spriteKeys.player2)
    const x = player2Sprite.x
    const y = player2Sprite.y
    
    if (pizzaSprite.x === player2Sprite.x && pizzaSprite.y === player2Sprite.y) {
      stopBgMusic()
      
      clearTile(x, y)
      addSprite(x, y, spriteKeys.player2)
      giveMoney()

      if (!advancingLevel) {
              playTune(tune`
189.873417721519: E4/189.873417721519,
189.873417721519: D4/189.873417721519 + B5~189.873417721519,
189.873417721519: G5/189.873417721519 + F5/189.873417721519 + E5/189.873417721519 + B5~189.873417721519,
189.873417721519: A5/189.873417721519 + D5/189.873417721519 + C5/189.873417721519 + B4/189.873417721519 + A4/189.873417721519,
189.873417721519: G4/189.873417721519 + F4/189.873417721519 + A5~189.873417721519 + G5~189.873417721519 + F5~189.873417721519,
189.873417721519: G4/189.873417721519,
189.873417721519: A4/189.873417721519,
189.873417721519: B4/189.873417721519,
189.873417721519: C5/189.873417721519,
189.873417721519,
189.873417721519: A4/189.873417721519,
189.873417721519: G4/189.873417721519,
189.873417721519: F4/189.873417721519,
189.873417721519: E4/189.873417721519,
3417.721518987342`)
      setTimeout(playBgMusic, 3000)
      }
    }
  }

  if (advancingLevel) {return}
  if (doughSprite) {
      const oven = getFirst(spriteKeys.oven)
      if (!oven) {
        return
      }

      if (doughSprite.x === oven.x && doughSprite.y === oven.y) {
        setOvenFire(true)
        stopBgMusic()
        setTimeout(playBgMusic, 4000)

        playTune(doughInOvenSound)
       
        setTimeout(() => {
          setOvenFire(false)
          addSprite(2, 2, spriteKeys.pizza)
        }, 3 * 1000)
      }
  }
})
